#include "./BlockQueue.hpp"
// 测试阻塞队列
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <string>
#include <ctime>

using std::cout;
using std::cin;
using std::endl;

struct ThreadObject
{
    ThreadObject(const std::string& threadId, BlockQueue<int>& queue, int Sleep, int nums = 1)
    :_threadId(threadId), _queue(queue), _sleep(Sleep), _nums(nums)
    {}

    int _sleep;  // 消费时间
    int _nums;  // 生产者生产个数
    std::string _threadId;
    BlockQueue<int>& _queue;
};

// 生产者线程
void* ProThread(void* arg)
{
    ThreadObject* threadObject = (ThreadObject*)arg;
    // 每个线程创建数据
    int num = threadObject->_nums;
    for (int i = 0; i < num; ++i)
    {
        sleep(threadObject->_sleep);  // 生产时间
        int val = rand() % 10000;
        threadObject->_queue.Push(val);
        cout << threadObject->_threadId << "生产了数据" << val << endl;
    }
    cout << threadObject->_threadId << "完成任务退出......\n";
    delete threadObject;
    return nullptr;
}

// 消费者线程
void* ConThread(void* arg)
{
    ThreadObject* threadObject = (ThreadObject*)arg;
    int num = threadObject->_nums;
    for (int i = 0; i < num; ++i)
    {
        int val = threadObject->_queue.Pop();
        sleep(threadObject->_sleep);// 消费数据时间
        cout << threadObject->_threadId << "消费了数据" << val << endl;
    }
    cout << threadObject->_threadId << "完成任务退出......\n";
    delete threadObject;
    return nullptr;
}

int main()
{
    srand(time(nullptr));

    int proNums, conNums, proSleep, conSleep, valNums, nums;
    proNums = conNums = 1;  // 生产者消费者默认1
    cout << "-----------阻塞队列生产者消费者测试程序-----------\n";
    // 用户输入测试
    do
    {
        cout << "生产者的数量[1~10]: ";
        cin >> proNums;
    } while (proNums > 10 || proNums <= 0);
    do
    {
        cout << "生产者生产时间[0~6]s: ";
        cin >> proSleep;
    } while (proSleep < 0 || proSleep > 6);
    do
    {
        cout << "消费者的数量[1~10]: ";
        cin >> conNums;
    } while (conNums > 10 || conNums <= 0);
    do
    {
        cout << "消费者消费时间[0~6]s: ";
        cin >> conSleep;
    } while (conSleep < 0 || conSleep > 6);
    do
    {
        cout << "阻塞队列长度[1~30]: ";
        cin >> valNums;
    }while(valNums > 30 || valNums <= 0);
    do
    {
        cout << "生产和消费个数[1~10]: ";
        cin >> nums;
    } while (nums < 0 || nums > 10);


    // 开始测试
    // 创建阻塞队列
    BlockQueue<int> blockQueue(valNums);
    // 创建生产者线程和消费者线程
    pthread_t pthreads[proNums + conNums];
    for (int i = 0; i < proNums + conNums; ++i)
    {
        if (i < proNums)  // 生产者
        {
            ThreadObject* theadObject = new ThreadObject("生产者-" + std::to_string(i + 1), blockQueue, proSleep, nums); 
            pthread_create(pthreads + i, nullptr, ProThread, (void*)theadObject);
        }
        else  // 消费者
        {
            ThreadObject* theadObject = new ThreadObject("消费者-" + std::to_string(i - proNums + 1), blockQueue, conSleep, nums); 
            pthread_create(pthreads + i, nullptr, ConThread, (void*)theadObject);
        }
    }

    // 创建完毕后等待线程退出即可
    for (int i = 0; i < proNums + conNums; ++i)
    {
        pthread_join(pthreads[i], nullptr);  // 阻塞等待退出即可
    }
    cout << "---主线程退出, 本次测试完毕---\n";

    return 0;
}
